#include "stdafx.h"
#include "Markov.h"

#include "Engine.h"
#include "Filesystem.h"
#include "Textgen.h"

const float text_rt_aspect_ratio = 0.25f;
const int text_length = 200;
const int arc_points = 75;
const Color background = Color(6, 6, 6);
const Color arc_color = Color(84, 84, 118);
const Color rays_color = Color(28, 26, 32);

Markov::Markov(RendererPtr renderer, VectorBatchPtr vector_batch, SpriteBatchPtr sprite_batch, BitmapFontPtr font)
: renderer(renderer), vector_batch(vector_batch), sprite_batch(sprite_batch), font(font), prng(56794)
{
}

Markov::~Markov()
{
}

void Markov::init(boost::weak_ptr<Demo> owner)
{
	this->owner = owner;

	pattern1 = video_device->getTextureManager()->loadTexture2D("pattern1", Filesystem::redirect("pattern1.png"));
	
	vector_batch_effect = video_device->getEffectManager()->load("PatternVectorBatch", Filesystem::redirect("PatternVectorBatch.fx"));
	vector_batch_effect->setParamValue(vector_batch_effect->getParamBySemantic("PATTERN_TEXTURE"), 
		boost::shared_polymorphic_cast<BaseTexture>(pattern1));
	vector_batch->setEffect(vector_batch_effect);

	uint viewport_width, viewport_height;
	video_device->getViewport(viewport_width, viewport_height);

	blured_sprite_effect = 
		video_device->getEffectManager()->load("BluredSpriteBatch", Filesystem::redirect("BluredSpriteBatch.fx"));
	blured_sprite_effect->setParamValue(blured_sprite_effect->getParamBySemantic("TEXTURE_SIZE"),
		Vector4(float(1024/4), float(576/4), 0.0f, 0.0f));
	default_sprite_effect = video_device->getEffectManager()->get("SpriteBatch");

	
	offscreen_target1 = video_device->getTextureManager()->createRenderTarget("rt_glow0", 
		1024/4, 576/4, D3DFMT_A8R8G8B8);
	offscreen_target2 = video_device->getTextureManager()->createRenderTarget("rt_glow1", 
		1024/4, 576/4, D3DFMT_A8R8G8B8);
	text_target = video_device->getTextureManager()->createRenderTarget("rt_markov_text", 
		 viewport_height, uint(viewport_height * text_rt_aspect_ratio), D3DFMT_A8R8G8B8);

	textgenReseed(787); // Run
	while(text1.size() < text_length)
	{
		text1 += textgenWord() + " ";
	}

	textgenReseed(3831); // live
	while(text2.size() < text_length)
	{
		text2 += textgenWord() + " ";
	}

	textgenReseed(5041); // Quick,
	while(text3.size() < text_length)
	{
		text3 += textgenWord() + " ";
	}
}

void Markov::close()
{
}

void Markov::update(float t)
{
}

float beat1_factor(float t) {
	while(t >= 0.0f) {
		t -= 0.535714f;
	}
	return t*t;
}

void Markov::render(float t)
{
	// Text
	video_device->setClearColor(Color(255, 255, 255, 0));
	video_device->beginScene(true, false, false, text_target);
	sprite_batch->setVirtualResolution(576, int(576 * text_rt_aspect_ratio));
	font->draw(Vector2(1000.0f + -t * 100.0f, 0.0f), text1);
	font->draw(Vector2(1600.0f + -t * 180.0f, 40.0f), text2);
	font->draw(Vector2(1200.0f + -t * 140.0f, 80.0f), text3);
	sprite_batch->present();
	renderer->render();
	video_device->endScene();

	// Glow buffer
	video_device->setClearColor(background);
	video_device->beginScene(true, false, false, offscreen_target1);
	sprite_batch->setVirtualResolution(1024, 576);
	Vector2 center = smootherstep(Vector2(512.0f, 288.0f), 
		Vector2(60.0f + sin(t*3.0f)*4.0f, 120.0f + sin(t*2.0f + 5.0f)*3.0f), transformT(3.55f, 4.1f, t));
	float width = smoothstep(80.0f, 32.0f, transformT(0.0f, 0.15f, t));
	float beat = beat1_factor(t);
	float shift = 0.0f;
	if(t > 18.0f)
		shift = smoothstep(0.0f, -670.0f, transformT(18.0f, 20.0f, t));
	drawArc(Vector2(center.x+shift, center.y), 300.0f - beat*12.5f, width, 270.0f, smoothstep(225.0f, t * 50.0f, transformT(1.57f, 1.77f, t)));
	drawArc(Vector2(center.x+shift, center.y), 240.0f - beat*25.0f, width, 270.0f, smoothstep(225.0f, t * 60.0f, transformT(1.05f, 1.25f, t)));
	drawArc(Vector2(center.x+shift, center.y), 180.0f - beat*50.0f, width, 270.0f, smoothstep(225.0f, -t * 30.0f, transformT(0.5f, 0.7f, t)));
	drawArc(Vector2(center.x+shift, center.y), 360.0f - beat*6.25f, width, 270.0f, smoothstep(225.0f, t * 70.0f, transformT(2.1f, 2.3f, t)));
	drawRays(Vector2(800.0f + sin(t+0.2f) + shift, 460.0f + sin(t*1.4f)*2.0f), t*10.0f, 5, t);
	drawSnowflake(Vector2(300.0f + sin(t * 0.6f) * 300.f, 200.0f + cos(t * 0.5f) * 250.0f), 500.0f + cos(0.3f + t * 1.6f) * 100.0f,
		sin(t / 2.0f) + beat * 0.2f, t);
	vector_batch->present();
	renderer->render(1002, 1004);
	video_device->endScene();

	
	// Blur 1
	sprite_batch->setVirtualResolution(1024/4, 576/4);
	sprite_batch->setEffect(blured_sprite_effect);
	video_device->beginScene(true, false, false, offscreen_target2);
	sprite_batch->draw(offscreen_target1, 100, RectF(), Vector2(0.0f, 0.0f));
	sprite_batch->present(1);
	renderer->render(1100, 1100);
	video_device->endScene();

	// Blur 2
	video_device->beginScene(true, false, false, offscreen_target1);
	sprite_batch->draw(offscreen_target2, 200, RectF(), Vector2(0.0f, 0.0f));
	sprite_batch->present(0);
	renderer->render(1200, 1200);
	video_device->endScene();

	// Blur 3
	video_device->beginScene(true, false, false, offscreen_target2);
	sprite_batch->draw(offscreen_target1, 300, RectF(), Vector2(0.0f, 0.0f));
	sprite_batch->present(1);
	renderer->render(1300, 1300);
	video_device->endScene();

	// Blur 4
	video_device->beginScene(true, false, false, offscreen_target1);
	sprite_batch->draw(offscreen_target2, 400, RectF(), Vector2(0.0f, 0.0f));
	sprite_batch->present(0);
	renderer->render(1400, 1400);
	video_device->endScene();
	
	// Blur 5
	video_device->beginScene(true, false, false, offscreen_target2);
	sprite_batch->draw(offscreen_target1, 500, RectF(), Vector2(0.0f, 0.0f));
	sprite_batch->present(1);
	renderer->render(1500, 1500);
	video_device->endScene();

	// Blur 6
	video_device->beginScene(true, false, false, offscreen_target1);
	sprite_batch->draw(offscreen_target2, 600, RectF(), Vector2(0.0f, 0.0f));
	sprite_batch->present(0);
	renderer->render(1600, 1600);
	video_device->endScene();

	// Blur 7
	video_device->beginScene(true, false, false, offscreen_target2);
	sprite_batch->draw(offscreen_target1, 700, RectF(), Vector2(0.0f, 0.0f));
	sprite_batch->present(1);
	renderer->render(1700, 1700);
	video_device->endScene();

	// Blur 8
	video_device->beginScene(true, false, false, offscreen_target1);
	sprite_batch->draw(offscreen_target2, 800, RectF(), Vector2(0.0f, 0.0f));
	sprite_batch->present(0);
	renderer->render(1800, 1800);
	video_device->endScene();

	// Normal scene
	video_device->setClearColor(Color(0, 0, 0));
	video_device->beginScene();

	sprite_batch->setVirtualResolution(1024, 576);
	sprite_batch->setEffect(default_sprite_effect);
	sprite_batch->draw(text_target, 6, RectF(),
		RectF(540.0f+shift, 0.0f, 576.0f * text_rt_aspect_ratio, 576.0f));
	sprite_batch->draw(text_target, 5, RectF(),
		RectF(500.0f+shift, -60.0f, (576.0f+160.0f) * text_rt_aspect_ratio, 576.0f + 120.0f), Color(196, 196, 196, 64));
	sprite_batch->present(2);
	renderer->render(1002, 1006);

	//sprite_batch->setEffect(default_sprite_effect);
	//sprite_batch->draw(offscreen_target1, 1, RectF(), RectF(-8.0f, -8.0f, 1032.0f, 584.0f),
	//	Color::smoothstep(Color(255, 255, 255), Color(0, 0, 0), transformT(19.0f, 21.0f, t)));
	sprite_batch->draw(offscreen_target1, 1, RectF(), RectF(0.0f, 0.0f, 1024.0f, 576.0f),
		Color::smoothstep(Color(255, 255, 255), Color(0, 0, 0), transformT(19.0f, 21.0f, t)));
	sprite_batch->present(1);
	renderer->render(1001, 1001);

	video_device->endScene();
	renderer->endFrame();

	sprite_batch->setEffect(default_sprite_effect);
}

void Markov::drawArc(const Vector2& center, float radius, float thickness, float angle, float rotation, float wavyness)
{
	static std::vector<Vector2> points;
	points.clear();
	points.reserve(arc_points);

	float offset1 = radius - thickness/2.0f;
	float offset2 = radius + thickness/2.0f;

	for(uint i = 0; i < arc_points/2; ++i)
	{
		float t = float(i) / float(arc_points/2 - 1);
		float a = (rotation - angle/2.0f) + angle * t;
		float distance = offset2 + sin(t * pi * 8.0f) * wavyness;
		float dx = cos(radians(a)) * distance;
		float dy = sin(radians(a)) * distance;
		points.push_back(Vector2(center.x + dx, center.y + dy));
	}
	for(uint i = 0; i < arc_points/2; ++i)
	{
		float t = float(arc_points/2 - 1 - i) / float(arc_points/2 - 1);
		float a = (rotation - angle/2.0f) + angle * t;
		float distance = offset1 + sin(t * pi * 8.0f) * wavyness;
		float dx = cos(radians(a)) * distance;
		float dy = sin(radians(a)) * distance;
		points.push_back(Vector2(center.x + dx, center.y + dy));
	}

	vector_batch->drawPolygon(4, points, arc_color);
}

void Markov::drawRays(const Vector2& center, float rotation, uint amount, float t)
{
	assert(amount >= 3);

	float radius = 1000.0f;
	float angle = 180.0f / float(amount);

	for(uint i = 0; i < amount; ++i)
	{
		float fi = float(i*2);
		float a1 = radians(rotation + angle * fi);
		float a2 = a1 + radians(angle);
		Vector2 v1(center.x + cos(a1)*radius, center.y + sin(a1)*radius);
		Vector2 v2(center.x + cos(a2)*radius, center.y + sin(a2)*radius);
		Color c = Color::smoothstep(Color(0, 0, 0, 0), rays_color, transformT(3.55f, 4.1f, t));
		if(t > 19.0f)
			c = Color::smoothstep(rays_color, Color(0, 0, 0, 0), transformT(19.0f, 21.0f, t));
		vector_batch->drawTriangle(3, center, v1, v2, c);
	}
}

void Markov::drawKoch(const Vector2& p1, const Vector2& p2, uint levels, Color c) 
{
	Vector2 midpoint = (p1 + p2) / 2.0f;
	Vector2 normal(p2.y - p1.y, p1.x - p2.x);
	normal.normalize();

	Vector2 dir = p2 - p1;
	float length = dir.length();

	Vector2 new_point = midpoint + normal * sqrtf(dir.lengthSq() / 9.0f - dir.lengthSq() / 36.0f);

	vector_batch->drawTriangle(2, p1 + dir / 3.0f, new_point, p2 - dir / 3.0f, c);

	if(levels == 1)
		return;

	drawKoch(p1, p1 + dir / 3.0f, levels-1, c);
	drawKoch(p1 + dir / 3.0f, new_point, levels-1, c);
	drawKoch(new_point, p2 - dir / 3.0f, levels-1, c);
	drawKoch(p2 - dir / 3.0f, p2, levels-1, c);
}

void Markov::drawSnowflake(const Vector2& center, float size, float angle, float t)
{
	if(t < 8.0f)
		return;
	if(t > 17.5f)
		return;

	Color c;
	if(t <= 15.0f)
		c = Color::smoothstep(Color(32, 18, 16, 0), Color(32, 18, 14, 196), transformT(8.0f, 9.0f, t));
	else
		c = Color::smoothstep(Color(32, 18, 14, 196), Color(0, 0, 0, 0), transformT(15.0f, 17.5f, t));

	Vector2 up(0.0f, size);
	Vector2 p1 = center + up.getRotated(angle);
	Vector2 p2 = center + up.getRotated(angle + 2.0f * pi / 3.0f);
	Vector2 p3 = center + up.getRotated(angle + 4.0f * pi / 3.0f);

	vector_batch->drawTriangle(2, p1, p2, p3, c);

	drawKoch(p1, p2, 4, c);
	drawKoch(p2, p3, 4, c);
	drawKoch(p3, p1, 4, c);
}